home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / fsp-2.7 / fsp-2 / fsp / bsd_src / function.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-21  |  14.0 KB  |  612 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Cimarron D. Taylor of the University of California, Berkeley.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37.  
  38. #include "tweak.h"
  39. #ifdef HAVE_UNISTD_H
  40. #ifndef __hpux
  41. #include <unistd.h>
  42. #endif
  43. #endif
  44. #include <stdio.h>
  45. #ifdef STDC_HEADERS
  46. #include <stdlib.h>
  47. #endif
  48. #include "my-string.h"
  49. #ifndef VMS
  50. #include <sys/types.h>
  51. #include <sys/stat.h>
  52. #include <sys/param.h>
  53. #else
  54. #include "types.h"
  55. #include "stat.h"
  56. #include "param.h"
  57. #endif
  58. #ifdef HAVE_TZFILE_H
  59. #include <tzfile.h>
  60. #endif
  61.  
  62. #ifndef VMS
  63. #include <sys/wait.h>
  64. #else
  65. #include "wait.h"
  66. #endif
  67. #include "find.h"
  68.  
  69. #define    FIND_EQUAL    0
  70. #define    FIND_LESSTHAN    1
  71. #define    FIND_GREATER    2
  72.  
  73. #define    COMPARE(a, b) { \
  74.   switch(plan->flags) { \
  75.     case FIND_EQUAL: \
  76.       return(a == b); \
  77.     case FIND_LESSTHAN: \
  78.       return(a < b); \
  79.     case FIND_GREATER: \
  80.       return(a > b); \
  81.   } \
  82.   return(0); \
  83. }
  84.  
  85. #ifdef HAVE_ANSI_PROTO
  86. static PLAN *palloc (enum ntype t, int (*f)())
  87. #else
  88. static PLAN *palloc (t, f)
  89.     enum ntype t;
  90.     int (*f)();
  91. #endif
  92. {
  93.   PLAN *new;
  94.  
  95.   if (new = (PLAN *) malloc(sizeof(PLAN))) {
  96.     new->type = t;
  97.     new->eval = f;
  98.     new->flags = 0;
  99.     new->next = NULL;
  100.     return(new);
  101.   }
  102.   perror("palloc");
  103.   exit(1);
  104. }
  105.  
  106. extern int isoutput;
  107. extern int process;
  108.  
  109. /*
  110.  * find_parsenum --
  111.  *    Parse a string of the form [+-]# and return the value.
  112.  */
  113. static long find_parsenum PROTO4(PLAN *, plan, char *, option, char *, str,
  114.                  char *, endch)
  115. {
  116.   long value;
  117.   char *endchar;        /* pointer to character ending conversion */
  118.      
  119.   /* determine comparison from leading + or - */
  120.   switch(*str) {
  121.     case '+':
  122.       ++str;
  123.       plan->flags = FIND_GREATER;
  124.       break;
  125.     case '-':
  126.       ++str;
  127.       plan->flags = FIND_LESSTHAN;
  128.       break;
  129.     default:
  130.       plan->flags = FIND_EQUAL;
  131.       break;
  132.   }
  133.      
  134.   /*
  135.    * convert the string with strtol().  Note, if strtol() returns zero
  136.    * and endchar points to the beginning of the string we know we have
  137.    * a syntax error.
  138.    */
  139.   value = strtol(str, &endchar, 10);
  140.   if (!value && endchar == str || endchar[0] &&
  141.       (!endch || endchar[0] != *endch)) {
  142.     fprintf(stderr,"%s: %s", option, "illegal numeric value");
  143.     exit(1);
  144.   }
  145.   if (endch)
  146.     *endch = endchar[0];
  147.   return(value);
  148. }
  149.  
  150. /*
  151.  * -time n functions --
  152.  *
  153.  *    True if the difference between the file time and the
  154.  *    current time is n 24 hour periods.
  155.  *
  156.  */
  157.  
  158. static int find_time PROTO3(PLAN *, plan, struct stat *, sbuf,  char *, path)
  159. {
  160.   extern time_t now;
  161.  
  162.   /* with FSP sbuf.st_atime=sbuf.st_ctime=sbuf.st_mtime */
  163.   COMPARE((now - sbuf->st_atime + SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
  164. }
  165.  
  166.  
  167. PLAN * c_time PROTO1(char *, arg)
  168. {
  169.   PLAN *new;
  170.  
  171.   new = palloc(N_TIME, find_time);
  172.   new->t_data = find_parsenum(new, "-time", arg, NULL);
  173.   return(new);
  174. }
  175.  
  176. /*
  177.  * brace_subst --
  178.  *      Replace occurrences of {} in s1 with s2 and return the result string.
  179.  */
  180. void brace_subst PROTO4(char *, orig, char **, store, char *, path, int,len)
  181. {
  182.   register int plen;
  183.   register char ch, *p;
  184.  
  185.   plen = strlen(path);
  186.   for (p = *store; ch = *orig; ++orig)
  187.     if (ch == '{' && orig[1] == '}') {
  188.       while ((p - *store) + plen > len)
  189.         if (!(*store = (char *)realloc(*store, len *= 2))) {
  190.           perror("realloc");
  191.           client_done();
  192.           exit(1);
  193.         }
  194.       bcopy(path, p, plen);
  195.       p += plen;
  196.       ++orig;
  197.     } else
  198.       *p++ = ch;
  199.   *p = '\0';
  200. }
  201.  
  202. /*
  203.  * queryuser --
  204.  *      print a message to standard error and then read input from standard
  205.  *      input. If the input is 'y' then 1 is returned.
  206.  */
  207. int queryuser PROTO1(char **, argv)
  208. {
  209.   int ch, first, nl;
  210.  
  211.   fprintf(stderr, "\"%s", *argv);
  212.   while (*++argv) fprintf(stderr, " %s", *argv);
  213.   fprintf(stderr, "\"? ");
  214.   fflush(stderr);
  215.  
  216.   first = ch = getchar();
  217.   for (nl = 0;;) {
  218.     if (ch == '\n') {
  219.       nl = 1;
  220.       break;
  221.     }
  222.     if (ch == EOF) break;
  223.     ch = getchar();
  224.   }
  225.  
  226.   if (!nl) {
  227.     fprintf(stderr, "\n");
  228.     fflush(stderr);
  229.   }
  230.   return(first == 'y');
  231. }
  232.  
  233. /*
  234.  * [-exec | -ok] utility [arg ... ] ; functions --
  235.  *
  236.  *    True if the executed utility returns a zero value as exit status.
  237.  *    The end of the primary expression is delimited by a semicolon.  If
  238.  *    "{}" occurs anywhere, it gets replaced by the current pathname.
  239.  *    The current directory for the execution of utility is the same as
  240.  *    the current directory when the find utility was started.
  241.  *
  242.  *    The primary -ok is different in that it requests affirmation of the
  243.  *    user before executing the utility.
  244.  */
  245. static int find_exec PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  246. {
  247.   register int cnt;
  248.   pid_t pid;
  249. #ifndef HAVE_UNION_WAIT
  250.   int status;
  251. #else
  252.   union wait status;
  253. #endif
  254.  
  255.   for (cnt = 0; plan->e_argv[cnt]; ++cnt)
  256.     if (plan->e_len[cnt])
  257.       brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt], path,
  258.           plan->e_len[cnt]);
  259.  
  260.   if (plan->flags && !queryuser(plan->e_argv)) return(0);
  261.  
  262. #ifndef VMS
  263.   switch(pid = fork())
  264. #else
  265.   switch(pid = vfork())
  266. #endif
  267.    {
  268.     case -1:
  269.       perror ("fork");
  270.       exit(1);
  271.     case 0:
  272.       execvp(plan->e_argv[0], plan->e_argv);
  273.       perror ("execvp");
  274.       exit(1);
  275.   }
  276.   pid = wait(&status);
  277.  
  278.  return(pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
  279. }
  280.  
  281. char *emalloc_ffind PROTO1(unsigned int, len)
  282. {
  283.   char *p;
  284.  
  285.   if (p = (char *)malloc(len)) return((char *)p);
  286.   perror("malloc");
  287.   exit(1);
  288. }
  289.  
  290. /*
  291.  * c_exec --
  292.  *    build three parallel arrays, one with pointers to the strings passed
  293.  *    on the command line, one with (possibly duplicated) pointers to the
  294.  *    argv array, and one with integer values that are lengths of the
  295.  *    strings, but also flags meaning that the string has to be massaged.
  296.  */
  297. PLAN *c_exec PROTO2(char ***, argvp, int, isok)
  298. {
  299.   PLAN *new;            /* node returned */
  300.   register int cnt;
  301.   register char **argv, **ap, *p;
  302.  
  303.   isoutput = 1;
  304.     
  305.   new = palloc(N_EXEC, find_exec);
  306.   new->flags = isok;
  307.  
  308.   for (ap = argv = *argvp;; ++ap) {
  309.     if (!*ap) {
  310.       fprintf(stderr,"%s: no terminating", isok ? "-ok" : "-exec");
  311.       exit(1);
  312.     }
  313.     if (**ap == ';') break;
  314.   }
  315.  
  316.   cnt = ap - *argvp + 1;
  317.   new->e_argv = (char **)emalloc_ffind((unsigned int)cnt * sizeof(char *));
  318.   new->e_orig = (char **)emalloc_ffind((unsigned int)cnt * sizeof(char *));
  319.   new->e_len = (int *)emalloc_ffind((unsigned int)cnt * sizeof(int));
  320.  
  321.   for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
  322.     new->e_orig[cnt] = *argv;
  323.     for (p = *argv; *p; ++p)
  324.       if (p[0] == '{' && p[1] == '}') {
  325.            new->e_argv[cnt] = (char *)emalloc_ffind((unsigned int)MAXPATHLEN);
  326.           new->e_len[cnt] = MAXPATHLEN;
  327.           break;
  328.       }
  329.     if (!*p) {
  330.       new->e_argv[cnt] = *argv;
  331.       new->e_len[cnt] = 0;
  332.     }
  333.   }
  334.   new->e_argv[cnt] = new->e_orig[cnt] = NULL;
  335.  
  336.   *argvp = argv + 1;
  337.   return(new);
  338. }
  339.  
  340. int printtime_ffind PROTO1(time_t, ftime)
  341. {
  342.   int i;
  343.   char *longstring;
  344.  
  345.   longstring = (char *)ctime((long *)&ftime);
  346.   for (i = 4; i < 11; ++i) putchar(longstring[i]);
  347.  
  348. #define SIXMONTHS       ((DAYSPERNYEAR / 2) * SECSPERDAY)
  349.  
  350.   if (ftime + SIXMONTHS > time((time_t *)NULL))
  351.     for (i = 11; i < 16; ++i) putchar(longstring[i]);
  352.   else {
  353.     (void)putchar(' ');
  354.     for (i = 20; i < 24; ++i) putchar(longstring[i]);
  355.   }
  356.   putchar(' ');
  357. }
  358.  
  359. #define BLK(A) (((A)+1023)/1024)
  360.  
  361. void printlong_ffind PROTO2(char *, name, struct stat *, sb)
  362. {
  363.   char *modep;
  364.  
  365.   printf("%4ld ", BLK(sb->st_size));
  366.   modep = ((S_IFDIR & sb->st_mode)) ? "drwxrwxrwx" : "-rw-rw-rw-" ;
  367.   printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, 8, "nobody", 8, "nobody");
  368.  
  369.   printf("%8ld ", sb->st_size);
  370.   printtime_ffind(sb->st_mtime);
  371.   printf("%s", name);
  372.   putchar('\n');
  373. }
  374.  
  375. /*
  376.  * -ls functions --
  377.  *
  378.  *    Always true - prints the current sbuf to stdout in "ls" format.
  379.  */
  380. static int find_ls PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  381. {
  382.   printlong_ffind(path, sbuf);
  383.   return(1);
  384. }
  385.  
  386. PLAN *c_ls PROTO0((void))
  387. {
  388.   isoutput = 1;
  389.   return(palloc(N_LS, find_ls));
  390. }
  391.  
  392. /*
  393.  * -name functions --
  394.  *
  395.  *    True if the basename of the filename being examined
  396.  *    matches pattern using Pattern Matching Notation S3.14
  397.  */
  398. static int find_name PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  399. {
  400.   register char *name;
  401.  
  402.   /* extract filename */
  403.   for (name = path + strlen(path); name > path && *name != '/'; name--);
  404.   if (*name == '/') name++;
  405.   return(fnmatch(plan->c_data, name));
  406. }
  407.  
  408. PLAN *c_name PROTO1(char *, pattern)
  409. {
  410.   PLAN *new;
  411.  
  412.   new = palloc(N_NAME, find_name);
  413.   new->c_data = pattern;
  414.   return(new);
  415. }
  416.  
  417. /*
  418.  * -newer file functions --
  419.  *
  420.  *    True if the current file has been modified more recently
  421.  *    then the modification time of the file named by the pathname
  422.  *    file.
  423.  */
  424. static int find_newer PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  425. {
  426.   return(sbuf->st_mtime > plan->t_data);
  427. }
  428.  
  429. PLAN *c_newer PROTO1(char *, filename)
  430. {
  431.   PLAN *new;
  432.   struct stat sb;
  433.     
  434.   if (stat(filename, &sb)) {
  435.     perror("stat");
  436.     exit(1);
  437.   }
  438.   new = palloc(N_NEWER, find_newer);
  439.   new->t_data = sb.st_mtime;
  440.   return(new);
  441. }
  442.  
  443. /*
  444.  * -print functions --
  445.  *
  446.  *    Always true, causes the current pathame to be written to
  447.  *    standard output.
  448.  */
  449. static int find_print PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  450. {
  451.   (void)printf("%s\n", path);
  452.   return(1);
  453. }
  454.  
  455. PLAN *c_print PROTO0((void))
  456. {
  457.   isoutput = 1;
  458.  
  459.   return(palloc(N_PRINT, find_print));
  460. }
  461.  
  462. /*
  463.  * -prune functions --
  464.  *
  465.  *    Prune a portion of the hierarchy.
  466.  */
  467. static int find_prune PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  468. {
  469.   process = -1;
  470.   return(1);
  471. }
  472.  
  473. PLAN *c_prune PROTO0((void))
  474. {
  475.   return(palloc(N_PRUNE, find_prune));
  476. }
  477.  
  478. /*
  479.  * -size n[c] functions --
  480.  *
  481.  *    True if the file size in bytes, divided by an implementation defined
  482.  *    value and rounded up to the next integer, is n.  If n is followed by
  483.  *    a c, the size is in bytes.
  484.  */
  485. #define    FIND_SIZE    512
  486. static int divsize = 1;
  487.  
  488. static int find_size PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  489. {
  490.   off_t size;
  491.  
  492.   size = divsize ? ((sbuf->st_size + FIND_SIZE - 1)/FIND_SIZE) : sbuf->st_size;
  493.   COMPARE(size, plan->o_data);
  494. }
  495.  
  496. PLAN *c_size PROTO1(char *, arg)
  497. {
  498.   PLAN *new;
  499.   char endch='c';
  500.     
  501.   new = palloc(N_SIZE, find_size);
  502.   new->o_data = find_parsenum(new, "-size", arg, &endch);
  503.   if (endch == 'c') divsize = 0;
  504.   return(new);
  505. }
  506.  
  507. /*
  508.  * -type c functions --
  509.  *
  510.  *    True if the type of the file is c, where c is d or f for
  511.  *    directory or regular file, respectively.
  512.  */
  513. static int find_type PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  514. {
  515.   return((sbuf->st_mode & S_IFMT) == plan->m_data);
  516. }
  517.  
  518. PLAN *c_type PROTO1(char *, typestring)
  519. {
  520.   PLAN *new;
  521.   mode_t  mask;
  522.     
  523.   switch (typestring[0]) {
  524.     case 'd':
  525.       mask = S_IFDIR;
  526.       break;
  527.     case 'f':
  528.       mask = S_IFREG;
  529.       break;
  530.     default:
  531.       fprintf(stderr,"-type: unknown type");
  532.       exit(1);
  533.   }
  534.      
  535.   new = palloc(N_TYPE, find_type);
  536.   new->m_data = mask;
  537.   return(new);
  538. }
  539.  
  540. /*
  541.  * ( expression ) functions --
  542.  *
  543.  *    True if expression is true.
  544.  */
  545. int find_expr PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  546. {
  547.   register PLAN *p;
  548.   register int state;
  549.  
  550.   for(p=plan->p_data[0]; p && (state=(p->eval)(p, sbuf, path)); p=p->next);
  551.   return(state);
  552. }
  553.  
  554. /*
  555.  * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
  556.  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
  557.  * to a N_EXPR node containing the expression and the ')' node is discarded.
  558.  */
  559. PLAN *c_openparen PROTO0((void))
  560. {
  561.   return(palloc(N_OPENPAREN, (int (*)())-1));
  562. }
  563.  
  564. PLAN *c_closeparen PROTO0((void))
  565. {
  566.   return(palloc(N_CLOSEPAREN, (int (*)())-1));
  567. }
  568.  
  569.  
  570. /*
  571.  * ! expression functions --
  572.  *
  573.  *    Negation of a primary; the unary NOT operator.
  574.  */
  575. static int find_not PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  576. {
  577.   register PLAN *p;
  578.   register int state;
  579.  
  580.   for(p=plan->p_data[0]; p && (state=(p->eval)(p, sbuf, path)); p=p->next);
  581.   return(!state);
  582. }
  583.  
  584. PLAN *c_not PROTO0((void))
  585. {
  586.   return(palloc(N_NOT, find_not));
  587. }
  588.  
  589. /*
  590.  * expression -o expression functions --
  591.  *
  592.  *    Alternation of primaries; the OR operator.  The second expression is
  593.  * not evaluated if the first expression is true.
  594.  */
  595. static int find_or PROTO3(PLAN *, plan, struct stat *, sbuf, char *, path)
  596. {
  597.   register PLAN *p;
  598.   register int state;
  599.  
  600.   for(p=plan->p_data[0]; p && (state=(p->eval)(p, sbuf, path)); p=p->next);
  601.  
  602.   if (state) return(1);
  603.  
  604.   for(p=plan->p_data[1]; p && (state=(p->eval)(p, sbuf, path)); p=p->next);
  605.   return(state);
  606. }
  607.  
  608. PLAN *c_or PROTO0((void))
  609. {
  610.   return(palloc(N_OR, find_or));
  611. }
  612.